package no.nordicsemi.android.blinky;

import android.Manifest;
import android.app.AlertDialog;
import android.app.ProgressDialog;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothManager;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.pm.PackageManager;
import android.graphics.Bitmap;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.preference.PreferenceManager;
import android.provider.Settings;
import android.text.TextUtils;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.Toast;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.RequiresApi;
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.widget.Toolbar;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;
import butterknife.BindView;
import butterknife.ButterKnife;
import no.nordicsemi.android.ble.data.Data;
import no.nordicsemi.android.blinky.settings.SettingsActivity;
import no.nordicsemi.android.blinky.settings.SettingsFragment;
import no.nordicsemi.android.blinky.utils.BitmapUtils;
import no.nordicsemi.android.blinky.utils.DataHandlerUtils;
import no.nordicsemi.android.blinky.utils.ImageUtils;
import no.nordicsemi.android.blinky.utils.Qr;
import no.nordicsemi.android.blinky.utils.Utils;
import no.nordicsemi.android.blinky.wekeupble.WakeupManager;
import no.nordicsemi.android.blinky.wekeupble.WakeupManagerCallbacks;
import no.nordicsemi.android.support.v18.scanner.BluetoothLeScannerCompat;
import no.nordicsemi.android.support.v18.scanner.ScanCallback;
import no.nordicsemi.android.support.v18.scanner.ScanFilter;
import no.nordicsemi.android.support.v18.scanner.ScanResult;
import no.nordicsemi.android.support.v18.scanner.ScanSettings;

public class AutoActivity extends AppCompatActivity implements WakeupManagerCallbacks {
    private static final String TAG = AutoActivity.class.getSimpleName();
    /**
     * 用于存放筛选后的扫描结果
     */
    private List<ScanResult> mResults;
    private final static int REQUEST_PERMISSION_REQ_CODE = 34; // any 8-bit number

    private boolean mIsScanning = false;

    private final Handler mHandler = new Handler();

    private final static long SCAN_DURATION = 5000;
    @BindView(R.id.state_scanning)
    View mScanningView;
    @BindView(R.id.start_bt)
    Button start_bt;
    @BindView(R.id.qr)
    ImageView qr;
    private String deviceName;
    private String deviceAddress;
    private Bitmap qrCodeBitmap;
    private WakeupManager wakeupManager;
    private int width = 80;
    private int heitht = 80;
    private int reqid;
    private ArrayList<byte[]> totalData;
    private ProgressDialog dialog;
    private boolean userClickStop = false;
    private static final int ENABLE_BT_REQ = 0;
    private static final int REQUEST_ACCESS_COARSE_LOCATION = 1022; // random number

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_auto);
        ButterKnife.bind(this);
        final Toolbar toolbar = findViewById(R.id.toolbar);
        setSupportActionBar(toolbar);
        getSupportActionBar().setTitle("自动");
        mResults = new ArrayList<>();
        dialog = new ProgressDialog(this);

        //开启蓝牙
        if (!isBLEEnabled()) {
            showBLEDialog();
        }
        if (ContextCompat.checkSelfPermission(AutoActivity.this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager
                .PERMISSION_GRANTED) {
//            // When user pressed Deny and still wants to use this functionality, show the rationale
//            if (ActivityCompat.shouldShowRequestPermissionRationale(AutoActivity.this, Manifest.permission.ACCESS_COARSE_LOCATION)) {
//                return;
//            }
//            //开启权限
//            Utils.markLocationPermissionRequested(this);
            ActivityCompat.requestPermissions(
                    this,
                    new String[] { Manifest.permission.ACCESS_COARSE_LOCATION },
                    REQUEST_ACCESS_COARSE_LOCATION);
        }

        if (!Utils.isLocationRequired(this) || Utils.isLocationEnabled(this)) {
        } else {

            AlertDialog.Builder builder = new AlertDialog.Builder(AutoActivity.this);
            builder.setMessage("需要开启定位");
            builder.setPositiveButton("确定", new DialogInterface.OnClickListener() {
                @Override
                public void onClick(DialogInterface dialog, int which) {
                    //开启定位
                    final Intent intent = new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS);
                    startActivity(intent);
                }
            });

            builder.create().show();

        }


    }
    private boolean isBLEEnabled() {
        final BluetoothManager manager = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);
        final BluetoothAdapter adapter = manager.getAdapter();
        return adapter != null && adapter.isEnabled();
    }
    private void showBLEDialog() {
        final Intent enableIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
        startActivityForResult(enableIntent, ENABLE_BT_REQ);
    }
    /**
     * Scan for 5 seconds and then stop scanning when a BluetoothLE device is found then mLEScanCallback is activated This will perform regular scan for custom BLE Service UUID and then filter out.
     * using class ScannerServiceParser
     */
    private void startScan() {
        start_bt.setText("停止");

        mScanningView.setVisibility(View.VISIBLE);
        mResults.clear();
        // Since Android 6.0 we need to obtain either Manifest.permission.ACCESS_COARSE_LOCATION or Manifest.permission.ACCESS_FINE_LOCATION to be able to scan for
        // Bluetooth LE devices. This is related to beacons as proximity devices.
        // On API older than Marshmallow the following code does nothing.
        if (ContextCompat.checkSelfPermission(AutoActivity.this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager
                .PERMISSION_GRANTED) {
            // When user pressed Deny and still wants to use this functionality, show the rationale
            if (ActivityCompat.shouldShowRequestPermissionRationale(AutoActivity.this, Manifest.permission.ACCESS_COARSE_LOCATION)) {
                return;
            }

            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
                requestPermissions(new String[]{Manifest.permission.ACCESS_COARSE_LOCATION}, REQUEST_PERMISSION_REQ_CODE);
            }
            return;
        }


//		mAdapter.clearDevices();
//		mScanButton.setText(R.string.scanner_action_cancel);

        final BluetoothLeScannerCompat scanner = BluetoothLeScannerCompat.getScanner();
        final ScanSettings settings = new ScanSettings.Builder()
                .setScanMode(ScanSettings.SCAN_MODE_LOW_LATENCY).setReportDelay(1000).setUseHardwareBatchingIfSupported(false).build();
        final List<ScanFilter> filters = new ArrayList<>();
//		filters.add(new ScanFilter.Builder().setServiceUuid(mUuid).build());
        scanner.startScan(filters, settings, scanCallback);

        mIsScanning = true;
        mHandler.postDelayed(() -> {
            if (mIsScanning) {
                stopScan();
            }
        }, SCAN_DURATION);
    }


    private ScanCallback scanCallback = new ScanCallback() {
        @Override
        public void onScanResult(final int callbackType, final ScanResult result) {
            // do nothing
            Log.i(TAG, "onScanResult: -->" + result.toString());

        }

        @Override
        public void onBatchScanResults(final List<ScanResult> results) {
            mResults.clear();
            final SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(AutoActivity.this);
            String name = preferences.getString(SettingsFragment.SETTINGS_DFU_NAME, SettingsFragment.SETTINGS_DFU_NAME_DEFAULT);
            String rssi = preferences.getString(SettingsFragment.SETTINGS_DFU_RSSI, String.valueOf(SettingsFragment
                    .SETTINGS_DFU_RSSI_DEFAULT));


            Log.i(TAG,"name:-->"+name);
            for (ScanResult result : results) {
                if (TextUtils.isEmpty(name)) {
                    //不筛选设备
                    if (TextUtils.isEmpty(rssi)) {
                        //不筛选信号
                        mResults.add(result);
                    } else {
                        //筛选信号
                        if (result.getRssi() > Integer.parseInt(rssi)) {
                            mResults.add(result);
                        }
                    }

                } else {
                    //筛选设备
                    if (TextUtils.isEmpty(rssi)) {
                        //不筛选信号
                        if (result.getDevice().getName() != null && result.getDevice().getName().equals(name)) {
                            mResults.add(result);
                        }
                    } else {
                        //筛选信号
                        if (result.getDevice().getName() != null && result.getDevice().getName().equals(name) && result.getRssi
                                () > Integer.parseInt(rssi)) {
                            mResults.add(result);
                        }
                    }

                }

            }
            Log.i(TAG, "onBatchScanResults size--> " + mResults.size() + "-->" + mResults.toString());
        }

        @Override
        public void onScanFailed(final int errorCode) {
            // should never be called
        }
    };

    /**
     * Stop scan if user tap Cancel button
     */
    private void stopScan() {
        start_bt.setText("开始");

        mScanningView.setVisibility(View.INVISIBLE);

        if (mIsScanning) {
//			mScanButton.setText(R.string.scanner_action_scan);

            final BluetoothLeScannerCompat scanner = BluetoothLeScannerCompat.getScanner();
            scanner.stopScan(scanCallback);

            mIsScanning = false;
        }
        //5s 扫描完成后，选出信号最好的一个设备
        selectDevice();


    }


    /**
     * 如果用户没有点击停止，就接着搜索
     */
    private void reScan(){
        Log.d(TAG,"重新搜索");
        if (!mIsScanning) {
            if (userClickStop){
                return;
            }
            startScan();
        }
    }

    private void selectDevice() {
        Log.d(TAG, "搜索完成");
        if (mResults.isEmpty()) {
            Log.d(TAG, "没有搜索到设备");
            //接着搜索
            reScan();
            return;
        }
        Collections.sort(mResults, new Sortbyrssi());
        Log.i(TAG, "信号最好的设备：" + mResults.get(0).getRssi() + "-->" + mResults.toString());

//        mSelectedDevice = mResults.get(0).getDevice();
//        mUploadButton.setEnabled(mStatusOk);
//        mDeviceNameView.setText(mResults.get(0).getDevice().getName() != null ? mResults.get(0).getDevice().getName() : getString(R.string.not_available));
//
//        //选择出设备之后，开始链接
        BluetoothDevice device = mResults.get(0).getDevice();


        deviceAddress = device.getAddress();
        deviceName = TextUtils.isEmpty(device.getName()) ? "未知设备" : device.getName();

        connect(device);


    }

    /**
     * 连接设备
     *
     * @param device
     */
    private void connect(BluetoothDevice device) {
        wakeupManager = new WakeupManager(AutoActivity.this);
        wakeupManager.setGattCallbacks(this);
        wakeupManager.connect(mResults.get(0).getDevice()).useAutoConnect(false)
                .retry(3, 100)
                .enqueue();
    }

    /**
     * 开始扫描
     *
     * @param view
     */
    public void start(View view) {
        Log.i(TAG,"mIsScanning--->"+mIsScanning);
        if (mIsScanning) {
            stopScan();
            userClickStop = true;
        } else {
            startScan();
            userClickStop = false;

        }
    }

    @Override
    public void onDataReceived(BluetoothDevice device, Data data) {
        List<Integer> datas = DataHandlerUtils.bytesToArrayList(data.getValue());
        if (datas.get(4) == 0x87) {
            if (datas.get(5) == 1) {
                //可以开始发二维码图片
                if (reqid == 0) {
                    sendData();
                }
                //发送完成
                if (reqid != 0) {
                    Toast.makeText(AutoActivity.this, "发送完成", Toast.LENGTH_SHORT).show();

                    new Handler().postDelayed(new Runnable() {
                        @Override
                        public void run() {
                            wakeupManager.send(powerOff());
                            Log.d(TAG, "发送完成");
                            qr.setImageResource(R.mipmap.ic_launcher);
                            reScan();
                        }
                    },1000);



                }
                reqid = 0;

            }
        }
        if (datas.get(4) == 0x88) {
            reqid = datas.get(5);   //应答序列号
            sendData();
        }
    }

    @Override
    public void onDataReceived3(BluetoothDevice device, Data data) {

    }

    @Override
    public void onDataReceived4(BluetoothDevice device, Data data) {

    }

    @Override
    public void onDataSent(BluetoothDevice device, Data data) {

    }

    @Override
    public void onDataSent1(BluetoothDevice device, Data data) {

    }

    @Override
    public void onDataSent2(BluetoothDevice device, Data data) {

    }

    @Override
    public void onDeviceConnecting(@NonNull BluetoothDevice device) {
        Log.i(TAG, "onDeviceConnecting");
        showDialog();


    }

    @Override
    public void onDeviceConnected(@NonNull BluetoothDevice device) {
        Log.i(TAG, "onDeviceConnected");

    }

    @Override
    public void onDeviceDisconnecting(@NonNull BluetoothDevice device) {
        Log.i(TAG, "onDeviceDisconnecting");

    }

    @Override
    public void onDeviceDisconnected(@NonNull BluetoothDevice device) {
        Log.i(TAG, "onDeviceDisconnected");
        hideDialog();
        reScan();

    }

    @Override
    public void onLinkLossOccurred(@NonNull BluetoothDevice device) {
        Log.i(TAG, "onLinkLossOccurred");

    }

    @Override
    public void onServicesDiscovered(@NonNull BluetoothDevice device, boolean optionalServicesFound) {
        Log.i(TAG, "onServicesDiscovered");

    }

    @Override
    public void onDeviceReady(@NonNull BluetoothDevice device) {
        Log.i(TAG, "onDeviceReady");
        showQRcode();
        hideDialog();
        //发送数据
        wakeupManager.send(sendQrcode(1));
        Toast.makeText(AutoActivity.this,"正在发送！",Toast.LENGTH_SHORT).show();


    }

    @Override
    public void onBondingRequired(@NonNull BluetoothDevice device) {

    }

    @Override
    public void onBonded(@NonNull BluetoothDevice device) {

    }

    @Override
    public void onBondingFailed(@NonNull BluetoothDevice device) {

    }

    @Override
    public void onError(@NonNull BluetoothDevice device, @NonNull String message, int errorCode) {
        Log.i(TAG, "onError");
        hideDialog();
    }

    @Override
    public void onDeviceNotSupported(@NonNull BluetoothDevice device) {

    }


    class Sortbyrssi implements Comparator<ScanResult> {
        // Used for sorting in ascending order of
        // roll number
        public int compare(ScanResult a, ScanResult b) {
            return b.getRssi() - a.getRssi();
        }
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.setting, menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        switch (item.getItemId()) {
            case android.R.id.home:
                onBackPressed();
                break;

            case R.id.action_settings:
                final Intent intent = new Intent(this, SettingsActivity.class);
                startActivity(intent);
                break;
        }
        return true;
    }


    @Override
    protected void onStop() {
        super.onStop();
        if (wakeupManager != null) {
            Log.d(TAG, "onStop--> disconnect");
            wakeupManager.disconnect().enqueue();
        }
    }


    /**
     * 显示二维码
     */
    private void showQRcode() {
        String qrContent = deviceName + deviceAddress;
        String s = qrContent.replaceAll(":", "");

        int size = getResources().getDimensionPixelSize(R.dimen.bitmap_dialog_qr_size);
        qrCodeBitmap = Qr.bitmap(s, size);
        qr.setImageBitmap(qrCodeBitmap);

//        Log.i(TAG, "bitmapSize:" + BitmapUtils.getBitmapSize(qrCodeBitmap) + "\nwidth:" + qrCodeBitmap.getWidth() + "\nheight:" +
//                qrCodeBitmap.getHeight());
        Bitmap scale = ImageUtils.scale(qrCodeBitmap, 80, 80);
//        Log.i(TAG, "bitmapSize:" + BitmapUtils.getBitmapSize(scale) + "\nwidth:" + scale.getWidth() + "\nheight:" +
//                scale.getHeight());

        //获取数据
        totalData = getData(scale);


    }

    private void sendData() {
        byte[] data_to_send = totalData.get(reqid);
        wakeupManager.send(sendQrcodecontent(reqid, data_to_send));
    }

    private ArrayList<byte[]> getData(Bitmap scale) {
        //获取data
        int[] pixels = new int[80 * 80];
        scale.getPixels(pixels, 0, 80, 0, 0, 80, 80);
//        Log.i(TAG, "所有像素：" + Arrays.toString(pixels));
        StringBuilder builder = new StringBuilder();
        for (int i = 0; i < pixels.length; i++) {
            if (pixels[i] == -16777216) {
                builder.append("0");
            } else {
                builder.append("1");
            }
        }
        String content = builder.toString();
//        Log.v(TAG, "所有像素2：" + builder.toString());
        byte[] data = new byte[pixels.length / 8];
        for (int i = 0, j = 0; i < content.length(); i++, j++) {
            char a0 = content.charAt(i);
            char a1 = content.charAt(i + width);
            char a2 = content.charAt(i + width * 2);
            char a3 = content.charAt(i + width * 3);
            char a4 = content.charAt(i + width * 4);
            char a5 = content.charAt(i + width * 5);
            char a6 = content.charAt(i + width * 6);
            char a7 = content.charAt(i + width * 7);
            String buf = "" + a7 + a6 + a5 + a4 + a3 + a2 + a1 + a0;
            data[j] = (byte) (Integer.parseInt(buf, 2));
            if ((i + 1) % width == 0 && i > 0) {
                i = i + width * 7;
            }
        }
        ArrayList<byte[]> results = BitmapUtils.SplitList(data, 14);
        return results;
    }


    /**
     * 发送二维码
     *
     * @param view
     */
    public void send(View view) {
        wakeupManager.send(sendQrcode(1));

    }


    /**
     * 控制发送二维码图片
     *
     * @param control
     */
    public byte[] sendQrcode(int control) {
        byte[] bytes = new byte[6];
        bytes[0] = (byte) 0xAB;
        bytes[1] = (byte) 0;
        bytes[2] = (byte) 3;
        bytes[3] = (byte) 0xFF;
        bytes[4] = (byte) 0x87;
        bytes[5] = (byte) control;
        return bytes;
    }

    /**
     * 发送二维码图片信息
     *
     * @param req  序列号
     * @param data 字节数据
     */
    public byte[] sendQrcodecontent(int req, byte[] data) {
        int length = data.length;
        byte[] bytes = new byte[6];
        bytes[0] = (byte) 0xAB;
        bytes[1] = (byte) 0;
        bytes[2] = (byte) (length + 3);
        bytes[3] = (byte) 0xFF;
        bytes[4] = (byte) 0x88;
        bytes[5] = (byte) req;    //最大为255个数据包
        byte[] bytes2 = BitmapUtils.addBytes(bytes, data);
        return bytes2;
    }

    public byte[] powerOff() {
        byte[] bytes = new byte[6];
        bytes[0] = (byte) 0xAB;
        bytes[1] = (byte) 0;
        bytes[2] = (byte) 3;
        bytes[3] = (byte) 0xFF;
        bytes[4] = (byte) 0xFF;
        bytes[5] = (byte) 0x80;
        return bytes;
    }


    private void showDialog() {
        dialog.show();
        Log.d(TAG, "showDialog");

    }

    private void hideDialog() {
        if (dialog != null && dialog.isShowing()) {
            dialog.dismiss();
            Log.d(TAG, "hideDialog");
        }
    }
}
